#!/bin/sh -ef
#
# Copyright (C) 2003-2019  Dmitry V. Levin <ldv@altlinux.org>
# Copyright (C) 2006  Alexey Gladkov <legion@altlinux.org>
# 
# The hsh-rebuild utility for the hasher project
#
# SPDX-License-Identifier: GPL-2.0-or-later
#

. hsh-sh-functions

show_help()
{
	cat <<EOF
hsh-rebuild - rebuild source package in chroot prepared by hsh-initroot.

Usage: $PROG [options] [<path-to-workdir>] <source-package>

<path-to-workdir> must be valid writable directory.

Options:
  --args=ARGS                       a deprecated synonym for --rpmbuild-args;
  --build-srpm-only                 do not build binary packages, produce src.rpm only;
  --excludedocs                     do not install documentation files;
  --hasher-priv-dir=DIR             hasher-priv directory;
  --install-only                    do not build, stop after installing build dependencies;
  --mountpoints=LIST                comma-separated list of known mount points;
  --nodeps                          ignore package dependencies (dangerous);
  --no-sisyphus-check-in[=LIST]     do not run sisyphus_check input tests [specified in LIST];
  --no-sisyphus-check[=LIST]        do not run sisyphus_check tests [specified in LIST];
  --no-sisyphus-check-out[=LIST]    do not run sisyphus_check output tests [specified in LIST];
  --number=NUMBER                   subconfig identifier;
  --query-repackage                 repackage the source before query for requirements (default);
  --no-query-repackage              do not repackage the source before query for requirements;
  --query-req-prog=FILE             program to run to query for requirements instead of autogenerated script;
  --rebuild-prog=FILE               program to run for rebuild instead of autogenerated script;
  --repo=DIR                        repository directory;
  --repo-bin=DIR                    binary packages destination directory,
                                    overriding --repo option for binary packages;
  --repo-src=DIR                    source packages destination directory,
                                    overriding --repo option for source packages;
  --rpmbuild-args=ARGS              extra arguments for rpmbuild;
  --source-only                     do not build, stop after installing source package;
  --target=ARCH                     target architecture;
  --wait-lock                       wait for workdir and hasher-priv locks;
  --no-wait-lock                    do not wait for workdir and hasher-priv locks;
  --without-stuff                   do not generate apt index files;
  --with-stuff                      generate apt index files;
  -q, --quiet                       try to be more quiet;
  -v, --verbose                     print a message for each action;
  -V, --version                     print program version and exit;
  -h, --help                        show this text and exit.
    
Report bugs to http://bugs.altlinux.ru/

EOF
	exit
}

TEMP=`getopt -n $PROG -o $getopt_common_opts -l args:,build-srpm-only,excludedocs,hasher-priv-dir:,install-only,mountpoints:,nodeps,no-lock,no-sisyphus-check::,no-sisyphus-check-in::,no-sisyphus-check-out::,no-stuff,number:,query-repackage,no-query-repackage,query-req-prog:,rebuild-prog:,repo:,repo-bin:,repo-src:,rpmbuild-args:,save-fakeroot,source-only,target:,wait-lock,no-wait-lock,without-stuff,with-stuff,$getopt_common_longopts -- "$@"` ||
	show_usage
eval set -- "$TEMP"

nodeps=
install_only=
source_only=
build_srpm_only=
query_repackage_option=
while :; do
	case "$1" in
		--build-srpm-only) build_srpm_only=1
			;;
		--excludedocs) exclude_docs=--excludedocs
			;;
		--hasher-priv-dir)
			hasher_priv_dir="$(opt_check_dir "$1" "$2")"
			shift
			;;
		--install-only) install_only=1
			;;
		--mountpoints) shift; known_mountpoints="$1"
			;;
		--nodeps) nodeps=--nodeps
			;;
		--no-lock) no_lock=1
			;;
		--no-sisyphus-check) shift
			[ -n "$1" ] && no_sisyphus_check="$1" || no_sisyphus_check=all
			;;
		--no-sisyphus-check-in) shift
			[ -n "$1" ] && no_sisyphus_check_in="$1" || no_sisyphus_check_in=all
			;;
		--no-sisyphus-check-out) shift
			[ -n "$1" ] && no_sisyphus_check_out="$1" || no_sisyphus_check_out=all
			;;
		--number)
			number="$(opt_check_number_ge_0 "$1" "$2")"
			shift
			;;
		--query-repackage)
			query_repackage=1
			query_repackage_option="$1"
			;;
		--no-query-repackage)
			query_repackage=
			query_repackage_option="$1"
			;;
		--query-req-prog)
			prog_query_req="$(opt_check_read "$1" "$2")"
			shift
			;;
		--rebuild-prog)
			prog_rebuild="$(opt_check_read "$1" "$2")"
			shift
			;;
		--repo) shift; repo="$1"
			;;
		--repo-bin) shift; repo_bin="$1"
			;;
		--repo-src) shift; repo_src="$1"
			;;
		--rpmbuild-args|--args) shift; rpmargs="$1"
			;;
		--source-only) source_only=1
			;;
		--save-fakeroot) message "Warning: obsolete option $1 ignored."
			;;
		--target) shift; target="$1"
			[ -z "${target##[A-Za-z]*}" ] ||
				fatal "--target: $target: invalid architecture."
			;;
		--wait-lock) lock_nowait=
			;;
		--no-wait-lock) lock_nowait=1
			;;
		--without-stuff|--no-stuff) no_stuff=1
			;;
		--with-stuff) no_stuff=
			;;
		--) shift; break
			;;
		*) parse_common_option "$1"
			;;
	esac
	shift
done

if [ -n "$prog_query_req" ] && [ -n "$query_repackage_option" ]; then
	show_usage "--query-req-prog and $query_repackage_option are mutually exclusive options."
fi

if [ -n "$build_srpm_only" ] && [ -n "$prog_rebuild" ]; then
	show_usage '--rebuild-prog does not make sense with --build-srpm-only.'
fi

if [ -z "$workdir" ]; then
	# Exactly two arguments.
	[ "$#" -ge 2 ] || show_usage 'Insufficient arguments.'
	[ "$#" -le 2 ] || show_usage 'Too many arguments.'
else
	# At least one and at most two arguments.
	[ "$#" -ge 1 ] || show_usage 'Insufficient arguments.'
	[ "$#" -le 2 ] || show_usage 'Too many arguments.'
fi

if [ "$#" -eq 2 ]; then
	set_workdir "$1"
	shift
else
	set_workdir
fi

source="$1"
[ -z "${source##/*}" ] || source="$saved_cwd/$source"

sname="${source##*/}"
shift

lock_workdir
[ -d "$chroot" ] || fatal "$chroot: cannot find chroot."
deduce_lock_hasher_priv

. hsh-sh-rebuild-functions

install_source_package

# Execute sisyphus_check for input.
run_sisyphus_check '$HOME/in/srpm' "$no_sisyphus_check_in"

[ -z "$source_only" ] || exit 0

# Calculate, check and install build dependencies.
if [ -z "$nodeps" ]; then
	# Create query script.
	if [ -n "$prog_query_req" ]; then
		install -p -m755 $verbose "$prog_query_req" chroot/.host/query_req >&2
	elif [ -n "$query_repackage" ] && [ "$source_package_type" = src.rpm ]; then
		# Unpack srpm and treat it as pkg.tar to calculate the build deps.
		# Since rpm-4.13, we could use rpmspec for a lightweight query instead
		# of creating an srpm; for now, we exclude the sources and patches.
		create_entry_header
		cat >>"$entry" <<__EOF__
cd "\$HOME/in/srpm"
${rpmi:-$def_rpmi} -i \\
	--define "_specdir \$HOME/in/spec" \\
	--define "_sourcedir \$HOME/in/source" \\
-- *
sed -i -r\\
	-e 's/^[[:blank:]]*(Source|Patch)([0-9]+)[[:blank:]]*:.*\$/&\nNo\1: \2/I' \\
	-e 's/^[[:blank:]]*(Source|Patch)[[:blank:]]*:.*\$/&\nNo\1: 0/I' \\
-- \$HOME/in/spec/*
__EOF__
		chrootuid2 </dev/null &&
			verbose "$sname: unpacked srpm." ||
			fatal "$sname: failed to unpack srpm."

		make_srpm_from_pkgtar '"$HOME/in/nosrpm"'

		# The repackaged in/nosrpm/*.(no)src.rpm is
		# only used to query the build dependencies;
		# the original in/srpm/*.src.rpm is used for the final rebuild.
		# It may seem that if the build dependencies have shrunk
		# after repackaging, then the final build could fail because
		# the original srpm would list more build dependencies.
		# This is not a problem, however, because rpmbuild --rebuild
		# calculates correctly the new set of build deps;
		# --nodeps is not needed for it to work properly.

		cat >chroot/.host/query_req <<__EOF__
#!/bin/sh -e
cd "\$HOME/in/nosrpm"
rpmquery -pR -- *.*src.rpm
__EOF__
	else
		cat >chroot/.host/query_req <<__EOF__
#!/bin/sh -e
rpmquery -pR -- "\$@"
__EOF__
	fi
	chmod 755 chroot/.host/query_req

	create_entry_header
	cat >>"$entry" <<__EOF__
cd "\$HOME/in/srpm"
/.host/query_req *
__EOF__

	calc_check_install_build_deps
	calculate_required_mountpoints "$build_deps"
	calculate_required_mountpoints_from_installed
fi

[ -z "$install_only" ] || exit 0

if [ -z "$build_srpm_only" ]; then
	# Create rebuild script.
	if [ -n "$prog_rebuild" ]; then
		install -p -m755 $verbose "$prog_rebuild" chroot/.host/rebuild >&2
	else
		cat >"chroot/.host/rebuild" <<__EOF__
#!/bin/sh -le
${verbose:+set -x}
export -n target ||:
SOURCE_DATE_EPOCH="\$(cat -- "\$HOME/in/SOURCE_DATE_EPOCH")"
export SOURCE_DATE_EPOCH
exec >&2 time rpmbuild --rebuild --target="\$target" $nodeps $rpmargs "\$@"
__EOF__
		chmod 755 "chroot/.host/rebuild"
		verbose 'Created rebuild script.'
	fi

	# Build the package.
	purge_chroot_out
	run_rebuild

	# Execute sisyphus_check for output.
	run_sisyphus_check '/.out' "$no_sisyphus_check_out" gpg
else
	create_entry_header
	cat >>"$entry" <<__EOF__
find "\$HOME/in/srpm" -mindepth 1 -maxdepth 1 -type f -name \*.src.rpm -print0 |
	xargs -r0 mv -f $verbose --target-directory=/.out/ -- >&2
__EOF__
	chrootuid2 </dev/null &&
		verbose "copying of src.rpm for \`$sname' complete." ||
		fatal "copying of src.rpm for \`$sname' failed."
fi

# Copy binaries from chroot.
case `find chroot/.out/ -mindepth 1 -maxdepth 1 -type f -name \*.src.rpm |LC_ALL=C grep -c '\.src\.rpm$'` in
	0|1) ;;
	*) fatal 'Too many src.rpm files written.' ;;
esac

make_repo
repo_bin="${repo_bin:-${repo:-$def_repo}/"${target:-$def_target}"/RPMS.hasher/}"
repo_src="${repo_src:-${repo:-$def_repo}/SRPMS.hasher/}"

find chroot/.out/ -mindepth 1 -maxdepth 1 -type f -name \*.src.rpm -print0 |
	xargs -r0 mv -f $verbose --target-directory="$repo_src" -- >&2

find chroot/.out/ -mindepth 1 -maxdepth 1 -type f -name \*.rpm -print0 |
	xargs -r0 mv -f $verbose --target-directory="$repo_bin" -- >&2

purge_chroot_out
